import datetime
import json
import logging

import pandas as pd
from PySide6 import QtWidgets
from PySide6.QtGui import Qt
from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QDialog, QDialogButtonBox, QLabel, QMessageBox, \
    QFileDialog

from kumquat_king_pyside6.app_config import ORDER_STATUS, BOOK_DATETIME_FORMAT, OLLAMA_CONFIG, HANDLER_ORDERS_PROMPTS, ORDER_MAPPINGS
from kumquat_king_pyside6.controls.apis import bulk_create_orders
from kumquat_king_pyside6.pages.ai_setting_dialog import AISettingDialog
from kumquat_king_pyside6.tools import get_ollama_models, request_ollama, clean_string, kumquat_format_converter, identify_orders, \
    message_box


class AddOrderPage(QWidget):
    def __init__(self, orderDf, kumquatFormat):
        super().__init__()
        self.orderDf = orderDf
        self.kumquatFormat = kumquatFormat
        self.aiConfig = OLLAMA_CONFIG
        self.setObjectName("ADD_ORDER_PAGE")
        self.init_base_ui()
        self.init_args()
        self.init_ui()
        self.init_slots()

    def init_args(self):
        self.customerNameEdits = []
        self.customerAddrEdits = []
        self.customerPhoneEdits = []
        self.kumquatFormatDropdowns = []
        self.kumquatSizeEdits = []
        self.onSoldEdits = []
        self.statusDropdowns = []
        self.presenterEdits = []
        self.noteEdits = []
        self.bookDateEdits = []

    def init_base_ui(self):
        self.addOrderLayout = QtWidgets.QVBoxLayout()  # Main layout
        self.addOrderScroll = QtWidgets.QScrollArea()
        self.ordersLayout = QVBoxLayout()
        self.ordersUI = QWidget()
        self.ordersUI.setLayout(self.ordersLayout)  # Orders Layout, will be scrollable

        self.setLayout(self.addOrderLayout)
        self.ordersLayout.setSpacing(5)
        self.ordersLayout.setContentsMargins(0, 0, 0, 0)

        # Parser UI, including text edit and submit button
        parserTextLayout = QHBoxLayout()
        self.parserEdit = QtWidgets.QTextEdit()
        self.parserEdit.setPlaceholderText("Put the order information.")
        self.parserEdit.setMaximumHeight(300)
        self.parserEdit.setAcceptRichText(False)

        self.parsedEdit = QtWidgets.QTextEdit()
        self.parsedEdit.setPlaceholderText("Parsed result will show here.")
        self.parsedEdit.setMaximumHeight(300)
        parserTextLayout.addWidget(self.parserEdit)
        parserTextLayout.addWidget(self.parsedEdit)

        parserBtnsLayout = QHBoxLayout()
        self.parserSubmitBtn = QtWidgets.QPushButton("解析结果")
        self.normalParsetrBtn = QtWidgets.QPushButton("普通解析")
        self.normalParsetrBtn.setToolTip("正常解析需要数据格式一一对齐,通常是csv或者excel上复制的格式")
        self.parserSubmitAIBtn = QtWidgets.QPushButton("AI解析")
        self.parserSubmitAIBtn.setToolTip("AI解析可以设置AI参数，AI解析主要用于数据格式混乱的内容，速度会慢一些")
        self.aiSettingBtn = QtWidgets.QPushButton("AI设置")
        parserBtnsLayout.addWidget(self.parserSubmitBtn)
        parserBtnsLayout.addWidget(self.normalParsetrBtn)
        parserBtnsLayout.addWidget(self.parserSubmitAIBtn)
        parserBtnsLayout.addWidget(self.aiSettingBtn)

        # Submit to Backend Button
        self.barBtnLayout = QHBoxLayout()
        self.viewJsonBtn = QtWidgets.QPushButton("查看JSON")
        self.submitBtn = QtWidgets.QPushButton("提交")
        self.barBtnLayout.addWidget(self.viewJsonBtn)
        self.barBtnLayout.addWidget(self.submitBtn)

        self.addOrderLayout.addLayout(parserTextLayout)
        self.addOrderLayout.addLayout(parserBtnsLayout)

        self.addOrderScroll.setWidgetResizable(True)
        self.addOrderScroll.setWidget(self.ordersUI)
        self.addOrderScroll.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
        self.addOrderScroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
        self.addOrderLayout.addWidget(self.addOrderScroll)
        self.addOrderLayout.addLayout(self.barBtnLayout)
        self.update_btn()

    def init_ui(self):
        bookTime = datetime.datetime.now().strftime(BOOK_DATETIME_FORMAT)
        if self.orderDf is None:
            customerNameEdit = self.gen_line_edit("", "请输入客户姓名")
            customerAddrEdit = self.gen_line_edit("", "请输入客户地址")
            customerPhoneEdit = self.gen_line_edit("", "请输入客户电话")

            kumquatFormatDropdown = QtWidgets.QComboBox()
            kumquatFormatList = [kumquat_format_converter(x['name'] + ' ' + x['style'], 'ST2ZH')
                                 for x in self.kumquatFormat]
            kumquatFormatDropdown.addItems(kumquatFormatList)

            kumquatSizeEdit = self.gen_line_edit("", "请输入数量")
            onSoldEdit = self.gen_line_edit("1", "请输入折扣")

            statusDropdown = QtWidgets.QComboBox()
            statusDropdown.addItems(ORDER_STATUS)
            statusDropdown.setCurrentIndex(0)

            presenterEdit = self.gen_line_edit("", "请输入线人")
            noteEdit = self.gen_line_edit("", "备注")
            bookDateEdit = self.gen_line_edit(bookTime, "预定时间, 默认为此刻")

            self.customerNameEdits.append(customerNameEdit)
            self.customerAddrEdits.append(customerAddrEdit)
            self.customerPhoneEdits.append(customerPhoneEdit)
            self.kumquatFormatDropdowns.append(kumquatFormatDropdown)
            self.kumquatSizeEdits.append(kumquatSizeEdit)
            self.onSoldEdits.append(onSoldEdit)
            self.statusDropdowns.append(statusDropdown)
            self.presenterEdits.append(presenterEdit)
            self.noteEdits.append(noteEdit)
            self.bookDateEdits.append(bookDateEdit)

            orderLayout = QHBoxLayout()
            orderLayout.addWidget(customerNameEdit)
            orderLayout.addWidget(customerAddrEdit)
            orderLayout.addWidget(customerPhoneEdit)
            orderLayout.addWidget(kumquatFormatDropdown)
            orderLayout.addWidget(kumquatSizeEdit)
            orderLayout.addWidget(onSoldEdit)
            orderLayout.addWidget(statusDropdown)
            orderLayout.addWidget(presenterEdit)
            orderLayout.addWidget(bookDateEdit)
            self.ordersLayout.addLayout(orderLayout)
        else:
            for index, row in self.orderDf.iterrows():
                # print(row)
                customerNameEdit = self.gen_line_edit(row['customer_name'], "请输入客户姓名")
                customerAddrEdit = self.gen_line_edit(row['customer_addr'], "请输入客户地址")
                customerPhoneEdit = self.gen_line_edit(str(row['customer_phoneNumber']), "请输入客户电话")
                kumquatFormatDropdown = QtWidgets.QComboBox()

                kumquatFormatList = [kumquat_format_converter(x['name'] + ' ' + x['style'], 'ST2ZH')
                                     for x in self.kumquatFormat]
                kumquatFormatDropdown.addItems(kumquatFormatList)

                if row.get('kumquat_name') and row.get('kumquat_format'):
                    kumquatFormatDropdown.setCurrentText(str(row['kumquat_name']) + ' ' + str(row['kumquat_format']))
                kumquatSizeEdit = self.gen_line_edit('1', "请输入数量")
                if row.get('quantity'):
                    kumquatSizeEdit.setText(str(row['quantity']))
                onSoldEdit = self.gen_line_edit("1", "请输入折扣")
                if row.get('on_sold'):
                    onSoldEdit.setText(str(row['on_sold']))

                statusDropdown = QtWidgets.QComboBox()
                statusDropdown.addItems(ORDER_STATUS)
                statusDropdown.setCurrentIndex(0)

                presenterEdit = self.gen_line_edit("ME", "请输入线人")
                if row.get('presenter'):
                    presenterEdit.setText(row['presenter'])
                noteEdit = self.gen_line_edit("", "备注")
                if row.get('note'):
                    noteEdit.setText(row['note'])
                if row.get('book_date'):
                    bookTime = row['book_date']
                bookDateEdit = self.gen_line_edit(bookTime, "预定时间, 默认为此刻")

                self.customerNameEdits.append(customerNameEdit)
                self.customerAddrEdits.append(customerAddrEdit)
                self.customerPhoneEdits.append(customerPhoneEdit)
                self.kumquatFormatDropdowns.append(kumquatFormatDropdown)
                self.kumquatSizeEdits.append(kumquatSizeEdit)
                self.onSoldEdits.append(onSoldEdit)
                self.statusDropdowns.append(statusDropdown)
                self.presenterEdits.append(presenterEdit)
                self.noteEdits.append(noteEdit)
                self.bookDateEdits.append(bookDateEdit)

                orderLayout = QHBoxLayout()
                orderLayout.addWidget(customerNameEdit)
                orderLayout.addWidget(customerAddrEdit)
                orderLayout.addWidget(customerPhoneEdit)
                orderLayout.addWidget(kumquatFormatDropdown)
                orderLayout.addWidget(kumquatSizeEdit)
                orderLayout.addWidget(onSoldEdit)
                orderLayout.addWidget(statusDropdown)
                orderLayout.addWidget(presenterEdit)
                orderLayout.addWidget(noteEdit)
                orderLayout.addWidget(bookDateEdit)
                self.ordersLayout.addLayout(orderLayout)

    def init_slots(self):
        self.parserSubmitBtn.clicked.connect(self.parse_text)
        self.parserSubmitAIBtn.clicked.connect(self.parse_by_ai)
        self.normalParsetrBtn.clicked.connect(self.local_parser)
        self.aiSettingBtn.clicked.connect(self.open_ai_setting)
        self.parserEdit.textChanged.connect(self.update_btn)
        self.parsedEdit.textChanged.connect(self.update_btn)
        self.viewJsonBtn.clicked.connect(self.view_json)
        self.submitBtn.clicked.connect(self.submit_orders)

    @staticmethod
    def gen_line_edit(text, placeholder):
        lineEdit = QtWidgets.QLineEdit()
        lineEdit.setPlaceholderText(placeholder)
        lineEdit.setText(text)
        lineEdit.setToolTip(placeholder)
        return lineEdit

    def clean_widget(self, layout):
        """
        Remove all the widget in current page
        :return:
        """
        if layout is not None:
            while layout.count():
                item = layout.takeAt(0)
                widget = item.widget()
                if widget is not None:
                    widget.deleteLater()
                else:
                    self.clean_widget(item.layout())

    def parse_text(self):
        handledList = clean_string(self.parsedEdit.toPlainText())
        try:
            handledList = json.loads(handledList)
            self.orderDf = pd.DataFrame(handledList)
            self.orderDf.fillna("", inplace=True)
            if not self.orderDf.empty:
                self.viewJsonBtn.setEnabled(True)
                self.submitBtn.setEnabled(True)
        except Exception as e:
            dlg = CustomDialog("解析失败", "请检查输入文本是否正确：" + str(e))
            if dlg.exec_() == QDialog.Accepted or dlg.exec_() == QDialog.Rejected:
                return
        # self.orderDf = identify_order(rawText)
        if self.orderDf is not None:
            self.clean_widget(self.ordersLayout)
            self.init_args()
            self.init_ui()

    def local_parser(self):
        """
        本地解析，如果数据格式固定
        :return:
        """
        rawData = self.parserEdit.toPlainText()
        self.orderDf = identify_orders(rawData)
        self.parsedEdit.setText(self.orderDf.to_json(orient='records', indent=4, force_ascii=False))

    def parse_by_ai(self):
        if self.parserEdit.toPlainText():
            prompt = self.parserEdit.toPlainText() + '\n' + self.aiConfig['prompt']
            self.parsedEdit.setText(request_ollama(self.aiConfig['host'],
                                                   prompt, self.aiConfig['choose_model']))

    def open_ai_setting(self):
        modelsRaw = get_ollama_models(self.aiConfig['host'])
        models = [model['name'] for model in modelsRaw]
        self.aiConfig['models'] = models
        self.aiConfig['prompt'] = HANDLER_ORDERS_PROMPTS
        dlg = AISettingDialog(self.aiConfig)
        if dlg.exec_() == QDialog.Accepted:
            newSettings = dlg.get_settings()
            self.aiConfig['choose_model'] = newSettings['model']
            self.aiConfig['prompt'] = newSettings['prompt']
            logging.info("UPDATE AI SETTINGS: " + str(self.aiConfig))
        else:
            logging.info("No setting changed.")

    def update_btn(self):
        self.parserSubmitBtn.setEnabled(False)
        self.parserSubmitAIBtn.setEnabled(False)
        self.submitBtn.setEnabled(False)
        self.viewJsonBtn.setEnabled(False)
        if len(self.parserEdit.toPlainText()) > 10:
            # self.parserSubmitBtn.setEnabled(True)
            self.parserSubmitAIBtn.setEnabled(True)
        if len(self.parsedEdit.toPlainText()) > 10:
            self.parserSubmitBtn.setEnabled(True)

    def build_json(self):
        self.orderDf['customer_presenter'] = [presenter.text() for presenter in self.presenterEdits]
        self.orderDf['kumquat_name'] = [kumquat_format_converter(kumquat.currentText())[0]
                                        for kumquat in self.kumquatFormatDropdowns]
        self.orderDf['kumquat_style'] = [kumquat_format_converter(kumquat.currentText())[1]
                                         for kumquat in self.kumquatFormatDropdowns]
        self.orderDf['quantity'] = [int(kumquatSize.text()) for kumquatSize in self.kumquatSizeEdits]
        self.orderDf['on_sold'] = [round(float(onSold.text()), 3) for onSold in self.onSoldEdits]
        self.orderDf['status'] = [status.currentText() for status in self.statusDropdowns]
        self.orderDf['book_date'] = [bookDate.text() for bookDate in self.bookDateEdits]
        self.orderDf['note'] = [note.text() if note.text() else 'None' for note in self.noteEdits]
        self.orderJson = self.orderDf.to_json(orient='records', force_ascii=False)
        logging.info("Order JSON: " + self.orderJson)

    def view_json(self):
        try:
            self.build_json()
            dlg = CustomDialog("查看JSON", json.dumps(json.loads(self.orderJson), indent=4, ensure_ascii=False))
            dlg.resize(600, 800)
            if dlg.exec_() == QDialog.Accepted or dlg.exec_() == QDialog.Rejected:
                dlg.close()
        except Exception as e:
            logging.error("Build Json failed: " + str(e))

    def submit_orders(self):
        self.build_json()
        dlg = CustomDialog("请检查数据", json.dumps(json.loads(self.orderJson), indent=4, ensure_ascii=False))
        dlg.resize(800, 800)
        if dlg.exec_() == QDialog.Accepted:
            res = bulk_create_orders(self.orderJson)
            if res[0] in [200, 201]:
                logging.info("Create order successfully!")
                self.orderDf = None
                self.clean_widget(self.ordersLayout)
                self.init_args()
                self.init_ui()
                self.parserEdit.setText("")
                self.update_btn()
                msgBox = CustomMSBox("成功", "创建订单成功 ")
                msgBox.exec()
            else:
                msgBox = CustomMSBox("创建订单失败", "请检查输入文本是否正确, error: " + res[1])
                msgBox.exec()
        else:
            return

    def load_from_file(self):
        logging.info("LOAD FROM FILE")
        fileName, _ = QFileDialog.getOpenFileName(self, "选择文件", "./data", "Excel Files (*.xlsx);; CSV File (*.csv)")
        if fileName:
            logging.info("File selected: " + fileName)
            try:
                if fileName.endswith(".xlsx"):
                    rawOrderDF = pd.read_excel(fileName)
                elif fileName.endswith(".csv"):
                    rawOrderDF = pd.read_csv(fileName)
                else:
                    message_box("Error", "Unsupported file type.")
                    return

                rawOrderDF.rename(columns=ORDER_MAPPINGS, inplace=True)
                self.orderDf = rawOrderDF
                self.orderDf['customer_phoneNumber'] = rawOrderDF['customer_phoneNumber'].astype(str)

                self.orderDf['book_date'] = pd.to_datetime(self.orderDf['book_date']).dt.strftime(BOOK_DATETIME_FORMAT)
                self.parsedEdit.setText(self.orderDf.to_json(orient='records', indent=4, force_ascii=False))
                # self.update_btn()
            except Exception as e:
                logging.error("Error loading file: " + str(e))
                message_box("Error", "Error loading file: " + str(e))
        else:
            logging.info("No file selected.")


class CustomDialog(QDialog):
    def __init__(self, title, text):
        super().__init__()
        # print(text)
        self.setWindowTitle(title)

        QBtn = (
                QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
        )

        self.buttonBox = QDialogButtonBox(QBtn)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        layout = QVBoxLayout()
        message = QtWidgets.QTextEdit()
        # html_content = f'<pre>{text}</pre>'
        message.setText(text)
        message.setReadOnly(True)
        message.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
        layout.addWidget(message)
        layout.addWidget(self.buttonBox)
        self.setLayout(layout)

    def close(self) -> bool:
        return super().close()


class CustomMSBox(QMessageBox):
    def __init__(self, title, text):
        super().__init__()

        self.setWindowTitle(title)

        self.setInformativeText(text)

        self.setDefaultButton(QMessageBox.StandardButton.Ok)
    def close(self) -> bool:
        return super().close()